#ifndef _NE_JOINT_H_
#define _NE_JOINT_H_

#include <common/Object.h>
#include <mathematics/Node.h>

namespace ne
{
    class Skeleton;

    class NEAPI Joint : public Node, public Object
    {
        friend class Skeleton;

        public:
            // Constructor, should not be called directly
            Joint(Skeleton *creator, const uint16_t handle, const std::string &name);

            virtual Joint* createChild(const uint16_t handle,
                                       const std::string &name,
                                       const Vector3 &position = Vector3::ZERO,
                                       const Quaternion &orientation = Quaternion::IDENTITY,
                                       const Vector3 &scale=Vector3::ONE);

            virtual bool destroyChild(Joint *child);

            virtual bool destroyChild(const std::string &name);

            virtual void destroyAllChildren();
            
            virtual void setObjectName(const std::string &name);

            uint16_t getHandle() const;

            void setBinding();

            virtual void setManuallyControlled(const bool manuallyControlled);

            bool isManuallyControlled() const;

            // Used for World Transform
            void getOffsetTransformMatrix(Matrix4 &m) const;

            virtual void needUpdate(const bool forceParentUpdate);

            virtual ~Joint();

        protected:
            virtual void _setHandle(const uint16_t handle);

            const Vector3& _getBindDerivedInversePosition() const;

            const Quaternion& _getBindDerivedInverseOrientation() const;

            const Vector3& _getBindDerivedInverseScale() const;

        private:
            Joint();

            Joint(const Joint &);

            Joint& operator = (const Joint &);

        public:
            static const uint16_t MAX_JOINT_HANDLE;
            static const uint16_t JOINT_NO_PARENT_HANDLE;

        protected:
            Skeleton *mCreator;
            uint16_t mHandle;

            // The inversed derived of the joint in the binding pose
            Vector3 mBindDerivedInversePosition;
            Quaternion mBindDerivedInverseOrientation;
            Vector3 mBindDerivedInverseScale;

            bool mManuallyControlled;
    };

    typedef std::vector<Joint*> JointVector;
    typedef JointVector::iterator JointVectorIterator;
    typedef JointVector::const_iterator JointVectorConstIterator;
    typedef std::set<Joint*> JointSet;
    typedef JointSet::iterator JointSetIterator;
    typedef JointSet::const_iterator JointSetConstIterator;
    typedef std::map<uint16_t, Joint*> JointHandleMap;
    typedef JointHandleMap::iterator JointHandleMapIterator;
    typedef JointHandleMap::const_iterator JointHandleMapConstIterator;
    typedef std::map<std::string, Joint*> JointNameMap;
    typedef JointNameMap::iterator JointNameMapIterator;
    typedef JointNameMap::const_iterator JointNameMapConstIterator;
}

#endif

